#include "RunTest.h"


/* ----- Test Class Test -------------------------------------------------------------------------------------------- */

/*
  Test the test class
  */
void RunTest::testTest(int whichTest, Correlation *c, Data *d, Test *t) {

    // Test isEqual()
    t->resetTracking();
    t->isEqual(1, t->isEqual(-3, -3, true));
    t->isEqual(1, t->isEqual(8.4, 8.4, true));

    t->isEqual(0, t->isEqual(3, 4, true));
    t->isEqual(0, t->isEqual(-4, -3, true));

    t->isEqual(-1, t->isEqual(4, 3, true));
    t->isEqual(-1, t->isEqual(-3, -4, true));

    t->isEqual(6, t->getSCount());
    t->isEqual(0, t->getFCount());

    // Show error message if a failure occurs
    bool testTest(true);
    if(!( t->getSCount() == 8 && t->getFCount() == 0 )) {
        cout << "Testing isEqual() failed." << endl;
        cout << endl;
        testTest = false;

        // Globally track the test or test suite outcomes, as appropriate
        ++fCountGlobal;

    } else {

        // Global test result tracking
        ++sCountGlobal;

    }

    // Reset tracking
    t->resetTracking();

    // Test assertEqual()
    t->isEqual(1, t->assertEqual(100, 100, "Test 0", true));
    t->isEqual(0, abs(t->getError() + t->getPError()));
    t->isEqual(0, t->assertEqual(100, 120, "Test 1", true));
    t->isEqual(20, t->getError());
    t->isEqual(20, t->getPError());
    t->isEqual(1, t->assertEqual(3, 3, "Test 2", true));
    t->isEqual(0, t->assertEqual(2, 3, "Test 3", true));
    t->isEqual(1, t->assertEqual(3.14, 3.14, "Test 4", true));
    t->isEqual(0, t->assertEqual(2.14, 3.14, "Test 5", true));
    t->isEqual(1, t->assertEqual(true, true, "Test 6", true));
    t->isEqual(-1, t->assertEqual(true, false, "Test 7",true));
    t->isEqual(1, t->assertEqual('a', 'a', "Test 8", true));
    t->isEqual(-1, t->assertEqual('b', 'a', "Test 9", true));

    // Show error message if a failure occurs
    if(!( t->getSCount() == 13 && t->getFCount() == 0 )) {
        cout << "Testing assertEqual() failed." << endl;
        cout << endl;
        testTest = false;

        // Global test result tracking
        ++fCountGlobal;

    } else {

        // Global test result tracking
        ++sCountGlobal;

    }

    // Reset tracking
    t->resetTracking();

    // Test internal success/failure tracking
    t->isEqual(3, 3);
    t->isEqual(2, 3);
    t->isEqual(3.14, 3.14);
    t->isEqual(2.14, 3.14);
    t->isEqual(true, true);
    t->isEqual(true, false);
    t->isEqual('a', 'a');
    t->isEqual('b', 'a');

    // Show error message if a failure occurs
    int sc = t->getSCount();
    int fc = t->getFCount();
    t->resetTracking();
    if(!( t->isEqual(4, sc) && t->isEqual(4, fc) )) {
        cout << "Testing internal counting failed." << endl;
        cout << endl;
        testTest = false;

        // Global test result tracking
        ++fCountGlobal;

    } else {

        // Global test result tracking
        ++sCountGlobal;

    }

    // Store results of test suite
    //   Note: Test sub-suites are reported by the reportStatus() function as tests. In other words several tests
    //   are run for each function of the test class. The results of several tests for each test class function
    //   are reported as a single test result.
    t->isEqual(true, testTest);

    // Global test result tracking
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();

    return;
}


/* ----- Class Implementation Functions ----------------------------------------------------------------------------- */

/*
  Test the correlation constructor function
  */
void RunTest::correlationConstructor(int whichTest, Correlation *c, Data *d, Test *t) {

    // Run tests
    t->isEqual(d->colorSpace, c->colorSpace);

    return;
}


/* ----- Level 0 Functions ------------------------------------------------------------------------------------------ */

/*
  Test the analyzeImage function

  This function tests images generated by testCaseData.nb. Only the first and last images in a sequence (defined by
  whichTest) are effectively used to check the strain calculation. The intermediate images exist simply to ensure that
  points do not wander excessively between time steps. This maximum distance is c->migration_dist_thresh.
  */
bool RunTest::analyzeImage(int whichTest, Correlation *c, Data *d, Test *t) {

    // Switch test options
    bool debugShowPF = false;
    bool debugShowStrain = true;
    bool positionUseAbsErr = false;
    bool strainUseAbsErr = false;
    if(positionUseAbsErr) {
        positionTol = 2;  // Units are pixels
    } else {
        positionTol = 5;  // Percent error
    }
    if(strainUseAbsErr) {
        strainTol = 0.12; //0.116;  //0.12; ///0.06;  // Units are dimensionless strain
    } else {
        strainTol = 6.3;  // Percent error
    }

    // Initialize
    c->debugParam = false;
    sCountGlobal = 0;
    fCountGlobal = 0;
    t->resetTracking();

    // Execute function for the first test image

    int screenWidth(1280), screenHeight(800);

    // Resize windows
    cvNamedWindow("Processed Image", CV_WINDOW_NORMAL);
    cvResizeWindow("Processed Image", screenWidth/3, screenHeight/2);
    cvMoveWindow("Processed Image", screenWidth/2, screenHeight/4);
    c->analyzeImage(d->pathNames[0], d->pathNames[1], d->fileNames[0], true);
    int numRefDots = c->num_dots;

    // Output and wait for user key press
    c->outputImage();
    int key = -1;
    while(key == -1) { key = cvWaitKey(10); }

    // Iterate over all test images
    for(int i = 1; i < 1000; ++i) {

        // Execute function for the set of test images
        if( i == 10 || (whichTest == 3 && i == 10) || (whichTest == 8 && i == 10) ) { c->debugParam = true; } else { c->debugParam = false; }



        if( !c->analyzeImage(d->pathNames[0], d->pathNames[1], d->fileNames[i], false) ) {
            continue;
        }

        // Output and wait for user key press
        c->outputImage();

        for(int p = 0; p < c->num_dots; p++) {
            int x = d->positionField[0][p] + c->pfRefRectangle.x;
            int y = d->positionField[1][p] + c->pfRefRectangle.y;
            c->imgProc[ y ][ x ].c1 = 255;
            c->imgProc[ y ][ x ].c2 = 0;
            c->imgProc[ y ][ x ].c3 = 0;
        }

        cvShowImage("Processed Image", c->imgProc.imgp);

        key = -1;
        while(key == -1) { key = cvWaitKey(10); }
    }








//    cout << "Expected position field:" << endl;
//    for(int p = 0; p < c->num_dots; p++) {
//        cout << d->positionField[0][p] << " " << d->positionField[1][p] << endl;
//    }
//    cout << "Actual position field:" << endl;
//    for(int p = 0; p < c->num_dots; p++) {
//        cout << c->positionField[0][p] << " " << c->positionField[1][p] << endl;
//    }
//    cout << endl;
//    cout << endl;






//    cout << "Reference position field before translation:" << endl;
//    for(int p = 0; p < c->num_dots; p++) {
//        cout << c->positionField_ref[0][p] << " " << c->positionField_ref[1][p] << endl;
//    }
//    cout << endl;
//    cout << "Position field before translation:" << endl;
//    for(int p = 0; p < c->num_dots; p++) {
//        cout << c->positionField[0][p] << " " << c->positionField[1][p] << endl;
//    }
//    cout << endl;


    // Correct position field with simple translation
    //   This is done to match the range of test data.
    //   Note: This translation is applied once after the complete image sequence whichTest has been completed.
    for(int p = 0; p < c->num_dots; p++) {

        // Shifting both reference and deformed position fields by the same quantity
        c->positionField_ref[0][p] -= c->pfRefRectangle.x;
        c->positionField_ref[1][p] -= c->pfRefRectangle.y;
        if(c->positionField[0][p] != -1) {
            c->positionField[0][p] -= c->pfRefRectangle.x;
            c->positionField[1][p] -= c->pfRefRectangle.y;
        }
    }

//    cout << "Reference position field after translation:" << endl;
//    for(int p = 0; p < c->num_dots; p++) {
//        cout << c->positionField_ref[0][p] << " " << c->positionField_ref[1][p] << endl;
//    }
//    cout << endl;
//    cout << "Position field after translation:" << endl;
//    for(int p = 0; p < c->num_dots; p++) {
//        cout << c->positionField[0][p] << " " << c->positionField[1][p] << endl;
//    }
//    cout << endl;
//    cout << endl;
//    cout << "num_blobs " << c->num_blobs << "  num_dots " << c->num_dots << endl;
//    cout << endl;












    // Make assertions about valid points in the reference position field
    bool hasBeenFound_ref[max_num_blobs] = {false};
    bool result0, result1;
    for(int p = 0; p < c->num_dots; ++p) {
        for(int pMatch = 0; pMatch < c->num_dots; ++pMatch) {

            if(!hasBeenFound_ref[pMatch]) {

                // Note: Position field units are pixels. Absolute tolerance units are also pixels.
                result0 = t->isClose( d->positionField_ref[0][p], c->positionField_ref[0][pMatch], positionTol, positionUseAbsErr, true);
                result1 = t->isClose( d->positionField_ref[1][p], c->positionField_ref[1][pMatch], positionTol, positionUseAbsErr, true);


//                cout << "pf_ref " << d->positionField_ref[0][p] << " " << c->positionField_ref[0][pMatch] << "      " << result0 << endl;
//                cout << "pf_ref " << d->positionField_ref[1][p] << " " << c->positionField_ref[1][pMatch] << "      " << result1 << endl;
//                cout << endl;

//                cout << "Strain field comparisons:  " << abs( abs(d->positionField_ref[0][p]) - abs(c->positionField_ref[0][pMatch]) ) << "  ";
//                cout << abs( abs(d->positionField_ref[1][p]) - abs(c->positionField_ref[1][pMatch]) ) << endl;
//                cout << result0 << " " << result1 << endl;
//                cout << endl;


                if(result0 && result1) {

                    // Calculation resulted in expected value for one point
                    t->isEqual(true, true);
                    hasBeenFound_ref[pMatch] = true;


                    if(debugShowPF) {

                        // GOOD PF OUTPUT
                        double dpf = d->positionField[0][p];
                        double cpf = c->positionField[0][pMatch];
                        printf("pf0 %f %f \t \t %f \t %f \n", dpf, cpf, abs(dpf) - abs(cpf), 100*(abs(dpf) - abs(cpf))/abs(dpf) );
                        dpf = d->positionField[1][p];
                        cpf = c->positionField[1][pMatch];
                        printf("pf1 %f %f \t \t %f \t %f \n", dpf, cpf, abs(dpf) - abs(cpf), 100*(abs(dpf) - abs(cpf))/abs(dpf) );
                        cout << endl;
                    }





                }
            }

        }
    }
    int result = t->assertEqual(numRefDots, t->getSCount(), "Tracking correct number of reference points");
    cout << "numRefDots " << numRefDots << endl;
    if(result == 1) { sCountGlobal++; } else { fCountGlobal++; }
    t->resetTracking();


    // Test for correct array initialization of reference position field
    result = 1;
    for(int p = c->num_dots; p < max_num_blobs; ++p) {

        result = t->isEqual(-1, c->positionField_ref[0][p], true);
        if(result != 1) { break; }

        result = t->isEqual(-1, c->positionField_ref[1][p], true);
        if(result != 1) { break; }
    }
    result = t->assertEqual(1, result, "Reference position field array initialization");
    if(result == 1) { sCountGlobal++; } else { fCountGlobal++; }
    t->resetTracking();


    // Test valid points in the position field
    bool hasBeenFound[max_num_blobs] = {false};
    for(int p = 0; p < c->num_dots; ++p) {
        for(int pMatch = 0; pMatch < c->num_dots; ++pMatch) {

            if(!hasBeenFound[pMatch]) {

                // Note: Position field units are pixels. Absolute tolerance units are also pixels.
                result0 = t->isClose( d->positionField[0][p], c->positionField[0][pMatch], positionTol, positionUseAbsErr, true);
                result1 = t->isClose( d->positionField[1][p], c->positionField[1][pMatch], positionTol, positionUseAbsErr, true);

                if(result0 && result1) {

                    // Calculation resulted in expected value for one point
                    t->isEqual(true, true);
                    hasBeenFound[pMatch] = true;

                }
            }

        }
    }
    result = t->assertEqual(c->num_dots, t->getSCount(), "Tracking correct number of deformed points");
    cout << "c->num_dots " << c->num_dots << endl;
    if(result == 1) { sCountGlobal++; } else { fCountGlobal++; }
    t->resetTracking();


    // Test for correct array initialization of position field
    result = 1;
    for(int p = c->num_dots; p < max_num_blobs; ++p) {

        result = t->isEqual(-1, c->positionField[0][p], true);
        if(result != 1) { break; }

        result = t->isEqual(-1, c->positionField[1][p], true);
        if(result != 1) { break; }
    }
    result = t->assertEqual(1, result, "Deformed position field array initialization");
    if(result == 1) { sCountGlobal++; } else { fCountGlobal++; }
    t->resetTracking();


    // Make assertions about the strain field values
    maxPError = -1;
    double pErrorXX, pErrorXY, pErrorYX, pErrorYY, pErrorPF;

    for(int p = 0; p < c->num_dots; ++p) {

        t->isClose( d->epsxx[0], c->epsxx[p], strainTol, positionUseAbsErr);
        t->isClose( d->epsxy[0], c->epsxy[p], strainTol, positionUseAbsErr);
        t->isClose( d->epsyx[0], c->epsyx[p], strainTol, positionUseAbsErr);
        t->isClose( d->epsyy[0], c->epsyy[p], strainTol, positionUseAbsErr);

        // Display expected strain values, actual strain values, difference, and percent error
        if(debugShowStrain) {

            // GOOD STRAIN OUTPUT
            printf("epsxx %f %f \t \t %f \t %f \n", d->epsxx[0], c->epsxx[p], (abs(d->epsxx[0]) - abs(c->epsxx[p])), 100*(abs(d->epsxx[0]) - abs(c->epsxx[p]))/abs(d->epsxx[0]) );
            printf("epsxy %f %f \t \t %f \t %f \n", d->epsxy[0], c->epsxy[p], (abs(d->epsxy[0]) - abs(c->epsxy[p])), 100*(abs(d->epsxy[0]) - abs(c->epsxy[p]))/abs(d->epsxy[0]) );
            printf("epsyx %f %f \t \t %f \t %f \n", d->epsyx[0], c->epsyx[p], (abs(d->epsyx[0]) - abs(c->epsyx[p])), 100*(abs(d->epsyx[0]) - abs(c->epsyx[p]))/abs(d->epsyx[0]) );
            printf("epsyy %f %f \t \t %f \t %f \n", d->epsyy[0], c->epsyy[p], (abs(d->epsyy[0]) - abs(c->epsyy[p])), 100*(abs(d->epsyy[0]) - abs(c->epsyy[p]))/abs(d->epsyy[0]) );
            cout << endl;
        }

    }
    result = t->assertEqual(4*c->num_dots, t->getSCount(), "Correct strain values test");
    if(result == 1) { sCountGlobal++; } else { fCountGlobal++; }
    t->resetTracking();


    // Test for correct array initialization of position field
    result = 1;
    for(int p = c->num_dots; p < max_num_blobs; ++p) {

        result = t->isEqual(0, c->epsxx[p], true);
        if(result != 1) { break; }

        result = t->isEqual(0, c->epsxy[p], true);
        if(result != 1) { break; }

        result = t->isEqual(0, c->epsyx[p], true);
        if(result != 1) { break; }

        result = t->isEqual(0, c->epsyy[p], true);
        if(result != 1) { break; }

    }
    result = t->assertEqual(1, result, "Strain field array initialization");
    if(result == 1) { sCountGlobal++; } else { fCountGlobal++; }
    t->resetTracking();


    // Compile test suite results
    for(int s = 0; s < sCountGlobal; ++s) {
        t->isEqual(true, true);
    }
    for(int f = 0; f < fCountGlobal; ++f) {
        t->isEqual(true, false);
    }














    //    cout << "Expected reference position field:" << endl;
    //    for(int p = 0; p < c->num_dots; p++) {
    //        cout << d->positionField_ref[0][p] << " " << d->positionField_ref[1][p] << endl;
    //    }
    //    cout << "Actual reference position field:" << endl;
    //    for(int p = 0; p < c->num_dots; p++) {
    //        cout << c->positionField_ref[0][p] << " " << c->positionField_ref[1][p] << endl;
    //    }
    //    cout << endl;
    //    cout << endl;










/*    // Display the contents of the position and strain fields
    cout << endl;
    cout << "Reference Position field:" << endl;
    for(int p = 0; p < c->num_blobs + 5; p++) {
        cout << c->positionField_ref[0][p] << " " << c->positionField_ref[1][p] << endl;
    }
    cout << endl;
    cout << "Position field:" << endl;
    for(int p = 0; p < c->num_blobs; p++) {
        cout << c->positionField[0][p] << " " << c->positionField[1][p] << endl;
    }
    cout << endl;
    cout << endl;
    cout << "Strain field:" << endl;
    for(int p = 0; p < c->num_blobs; p++) {
        cout << c->epsxx[p] << " " << c->epsxy[p] << " " << c->epsyx[p] << " " << c->epsyy[p] << endl;
    }
    */






    return true;
}

/*
  Test the storePositionField function
  */
void RunTest::storePositionField(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the storeStrainField function
  */
void RunTest::storeStrainField(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the outputImage function
  */
void RunTest::outputImage(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the outputOverlay function
  */
void RunTest::outputOverlay(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}



/* ----- Level 1 Functions ------------------------------------------------------------------------------------------ */


/*
  Test the loadPersistentValues function
  */
void RunTest::loadPersistentValues(int whichTest, Correlation *c, Data *d, Test *t) {
    return;
}


/*
  Test the savePersistentValues function
  */
void RunTest::savePersistentValues(int whichTest, Correlation *c, Data *d, Test *t) {
    return;
}


/*
  Test the inputImage function
  */
bool RunTest::inputImage(int whichTest, Correlation *c, Data *d, Test *t) {

    // Run tests
    //NOTE: Need to create a test case for filterImage().
//    d->loadInputImage();
    c->inputImage("./Test_Data_Programmatic/plt3.jpg");


    // Report test results and reset


//    sCountGlobal += t->getSCount();
//    fCountGlobal += t->getFCount();
//    t->resetTracking();

    return false;
}

/*
  Test the blobAnalysis function
  */
void RunTest::blobAnalysis(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the extractPositionField function
  */
void RunTest::extractPositionField(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the generateGridMap function
  */
void RunTest::generateGridMap(int whichTest, Correlation *c, Data *d, Test *t) {

    // Run tests
    d->generateGridMap(0, c);
    c->generateGridMap();
    t->assertEqualA361k(d->gridMap, c->gridMap, "generateGridMap() test 0");

    // Report and reset
    t->reportStatus("Testing generateGridMap()");
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();
    t->resetTracking();

    if(whichTest == 1) {

        // Display expected then actual gridMap
        cout << endl;
        for(int b = 0; b < 10; ++b) {
            for(int n = 0; n < max_neighbor_count; ++n) {
                cout << d->gridMap[n][b] << " ";
            }
            cout << endl;
        }
        cout << endl;
        for(int b = 0; b < 10; ++b) {
            for(int n = 0; n < max_neighbor_count; ++n) {
                cout << c->gridMap[n][b] << " ";
            }
            cout << endl;
        }
        cout << endl;
    }

    return;
}

/*
  Test the computeStrain function
  */
void RunTest::computeStrain(int whichTest, Correlation *c, Data *d, Test *t) {

    // Run tests
    d->computeStrain(0, c);
    c->computeStrain();
    for(int p = 0; p < max_num_blobs; ++p) {
        t->isClose(d->epsxx[p], c->epsxx[p]);
        t->isClose(d->epsxy[p], c->epsxy[p], pow(10, -5));
        t->isClose(d->epsyx[p], c->epsyx[p], pow(10, -5));
        t->isClose(d->epsyy[p], c->epsyy[p], pow(10, -5));
    }

    // Report results of tests
    t->reportStatus("Testing computeStrain()");
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();
    t->resetTracking();

    return;
}

/*
  Test the drawCurrentState function
  */
void RunTest::drawCurrentState(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}



/* ----- Level 2 Functions ------------------------------------------------------------------------------------------ */

/*
  Test the subsetImage function
  */
void RunTest::subsetImage(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the filterImage function
  */
void RunTest::filterImage(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the matchBlob function
  */
void RunTest::matchBlob(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the updateBoundingBox function
  */
void RunTest::updateBoundingBox(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the mergeBlobs function
  */
void RunTest::mergeBlobs(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the postProcess function
  */
void RunTest::postProcess(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the blobProbability function
  */
void RunTest::blobProbability(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the identifyDots function
  */
void RunTest::identifyDots(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the isValidPointSet function
  */
void RunTest::isValidPointSet(int whichTest, Correlation *c, Data *d, Test *t) {

    // Tests
    d->isValidPointSet(0, c);
    t->assertEqual(true, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 0");
    d->isValidPointSet(1, c);
    t->assertEqual(true, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 1");
    d->isValidPointSet(2, c);
    t->assertEqual(false, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 2");
    d->isValidPointSet(3, c);
    t->assertEqual(false, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 3");
    d->isValidPointSet(4, c);
    t->assertEqual(false, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 4");
    d->isValidPointSet(5, c);
    t->assertEqual(false, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 5");
    d->isValidPointSet(6, c);
    t->assertEqual(false, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 6");
    d->isValidPointSet(7, c);
    t->assertEqual(false, c->isValidPointSet(d->pt, d->ptStar, 0, 0, 0), "isValidPointSet() test 7");

    // Report results and reset
    t->reportStatus("Testing isValidPointSet");
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();
    t->resetTracking();

    return;
}

/*
  Test the localStrain function
  */
void RunTest::localStrain(int whichTest, Correlation *c, Data *d, Test *t) {

    // Tests
    d->localStrain(0, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 0");
    d->localStrain(1, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 1");
    d->localStrain(2, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 2");
    d->localStrain(3, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 3");
    d->localStrain(4, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 4");
    d->localStrain(5, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 5");
    d->localStrain(6, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 6");
    d->localStrain(7, c);
    c->localStrain(d->pt, d->ptStar, 0, 0);
    t->assertEqualA43(d->epsCollection, c->epsCollection, "localStrain() test 7");

    // Report status and reset
    t->reportStatus("Testing localStrain");
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();
    t->resetTracking();

    return;
}


/*
  Test the minAbs function
  */
double RunTest::minAbs(int whichTest, Correlation *c, Data *d, Test *t) {
    return 0;
}


/*
  Test the maxAbs function
  */
double RunTest::maxAbs(int whichTest, Correlation *c, Data *d, Test *t) {
    return 0;
}


/*
  Test the minIgnore function
  */
void RunTest::minIgnore(int whichTest, Correlation *c, Data *d, Test *t) {

    // Run tests
    t->assertEqual(2, c->minIgnore(2, 3), "minIgnore() test 0");
    t->assertEqual(-3, c->minIgnore(4, -3), "minIgnore() test 1");
    t->assertEqual(-8, c->minIgnore(-1, -8), "minIgnore() test 2");
    t->assertEqual(2, c->minIgnore(2, -1), "minIgnore() test 3");
    t->assertEqual(0, c->minIgnore(-1, -1), "minIgnore() test 4");

    // Report results and reset
    t->reportStatus("Testing minIgnore()");
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();
    t->resetTracking();

    return;
}

/*
  Test the maxIgnore function
  */
void RunTest::maxIgnore(int whichTest, Correlation *c, Data *d, Test *t) {

    // Run tests
    t->assertEqual(3, c->maxIgnore(2, 3), "maxIgnore() test 0");
    t->assertEqual(4, c->maxIgnore(4, -3), "maxIgnore() test 1");
    t->assertEqual(-8, c->maxIgnore(-1, -8), "maxIgnore() test 2");
    t->assertEqual(2, c->maxIgnore(2, -1), "maxIgnore() test 3");
    t->assertEqual(0, c->maxIgnore(-1, -1), "maxIgnore() test 4");

    // Report results and reset
    t->reportStatus("Testing maxIgnore()");
    sCountGlobal += t->getSCount();
    fCountGlobal += t->getFCount();
    t->resetTracking();

    return;
}

/*
  Test the drawBlobProperty function
  */
void RunTest::drawBlobProperty(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the drawCurrentPixel function
  */
void RunTest::drawCurrentPixel(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}

/*
  Test the debugHandle function
  */
void RunTest::debugHandle(int whichTest, Correlation *c, Data *d, Test *t) {

    //

    return;
}
